const { runInNewContext } = require("vm")

// new Function 解析模板字符串
let str = 'heelo${name} your${age}and${Bob.job}'
let obj = {
    name:'Bob',
    age:19,
    Bob:{
        job:'software'
    }
}

String.prototype.transform = function(param) {
        const fnStr = `return \`${this}\``
        const keys = Object.keys(param)
        const values = Object.values(param)
        const fn = new Function(...keys, fnStr)
        return fn(...values)
}
console.log(str.transform(obj))


// iterator 遍历器
let arr = [1,2,3,4]
let iter = arr[Symbol.iterator]()
let a = iter.next()
let b = iter.next()
let c = iter.next()
let d = iter.next()
let e = iter.next()

console.log(a,b,c,d,e);

function makeIteartor(interator) {
    let index = 0
    return {
        next:function() {
            return index < interator.length ? {value:interator[index++], done:false} : {value:undefined,done:true}
        }
    }
}
let next = makeIteartor(arr)
let a1 = next.next()
let a2 = next.next()
let a3 = next.next()
let a4 = next.next()
let a5 = next.next()
console.log(a1, a2, a3, a4, a5);

// 给对象部署遍历器 [Symbol.iterator]()
class RangeIterator {
    constructor(start, stop) {
      this.value = start;
      this.stop = stop;
    }
  
    [Symbol.iterator]() { return this; }
  
    next() {
      var value = this.value;
      if (value < this.stop) {
        this.value++;
        return {done: false, value: value};
      }
      return {done: true, value: undefined};
    }
  }
  
  function range(start, stop) {
    return new RangeIterator(start, stop);
  }
  
  for (var value of range(0, 3)) {
    console.log(value); // 0, 1, 2
  }

// 给对象部署遍历器 [Symbol.iterator]()
let Obj = {
    data: ['hello', 'world'],
    [Symbol.iterator]() {
        const self = this
        let index = 0
        return {
            next() {
                if(index < self.data.length) {
                    return {
                        value:self.data[index++],
                        done:false
                    }
                };
                return {done:true, value:undefined}
            }
        }
    }
}

for(let val of Obj) {
    console.log(val);
}


// Generator
function* Interator() {
    yield 'hello'
    yield 'world'
    return 'ending'
}

let inter = Interator()
let inter1 = inter.next()
let inter2 = inter.next()
let inter3 = inter.next()
console.log(inter1, inter2, inter3);


function* fibonacci() {
    let [prev, curr] = [0, 1];
    for (;;) {
      yield curr;
      [prev, curr] = [curr, prev + curr];
    }
  }
  
  for (let n of fibonacci()) {
    if (n > 1000) break;
    console.log(n);
  }

// 让对象拥有遍历属性
function* objectEntries() {
    let propKeys = Object.keys(this)
    for(let propkey of propKeys) {
        yield [propkey, jane[propkey]]
    }
}
let jane = {f1:'hello', f2:'world'}
function* fibonacci() {
  let [prev, curr] = [0, 1];
  for (;;) {
    yield curr;
    [prev, curr] = [curr, prev + curr];
  }
}

for (let n of fibonacci()) {
  if (n > 1000) break;
  console.log(n);
}
jane[Symbol.iterator] = objectEntries;
for(let [key, val] of jane) {
    console.log(key, val);
}


// yield* 后面接生成器函数 执行返回一个遍历器
function* bar() {
    yield 'x';
    yield* foo();
    yield 'y';
  }
  
  // 等同于
  function* foo() {
    yield 'x';
    yield 'a';
    yield 'b';
    yield 'y';
  }

  for(let i of bar()) {
    console.log(i);
  }

//  Generator 函数返回一个正常的对象实例，既可以用next方法，又可以获得正常的this
function* F() {
    this.a = 1;
    yield this.b = 2;
    yield this.c = 3;
  }
  var f = F.call(F.prototype);
  
  f.next();  // Object {value: 2, done: false}
  f.next();  // Object {value: 3, done: false}
  f.next();  // Object {value: undefined, done: true}
  
  f.a // 1
  f.b // 2
  f.c // 3



// 将F改成构造函数可new
function* gen() {
    this.a = 1;
    yield this.b = 2;
    yield this.c = 3;
  }
  
  function F() {
    // this指向gen.prototype
    return gen.call(gen.prototype);
  }
  
  var f = new F();
  
  f.next();  // Object {value: 2, done: false}
  f.next();  // Object {value: 3, done: false}
  f.next();  // Object {value: undefined, done: true}
  
  f.a // 1
  f.b // 2
  f.c // 3
  


//   给对象部署遍历器
  let myobj = {name:'csc', age:18}
  function* makeInerator(obj) {
    let keys = Object.keys(obj) 
    for(let key of keys) {
        yield [key, obj[key]]
    }
  }

  for(let [key, value] of makeInerator(myobj)) {
    console.log(key, value);
  }